﻿using System;
using NSubstitute;
using Phoenix.Frames;
using Phoenix.Framework;
using Xunit;

namespace Phoenix.Tests
{
    public class InvokeActionBuilderTests
    {
        readonly InvokeActionBuilder<BuilderController> builder;
        readonly ControllerActionContext context;

        public InvokeActionBuilderTests()
        {
            context = PhoenixObjectMother.CreateContext(ControllerAction.CreateFrom("Home.Main"));
            builder = new InvokeActionBuilder<BuilderController>(context);
        }

        [Fact]
        public void builder_supports_controlleractions()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");

            builder.InvokeAction(controllerAction).ActionInvoked(context, "BuilderController.Action");

            builder.InvokeActionCommand(controllerAction).CommandInvokes(context, "BuilderController.Action");

            builder.InvokeActionCommand<int>(controllerAction, arg=>new object[]{arg})
                .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 5 }, commandArgument: 5);

            builder.InvokeActionWithResult<int>(controllerAction)
                .ActionInvokedWithResult<int>(context, "BuilderController.Action");
        }

        [Fact]
        public void builder_supports_string_actionnames_with_parameters()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");

            builder.InvokeAction(controllerAction, new object[] { 1 })
                .ActionInvoked(context, "BuilderController.Action", parameters: new object[] { 1 });

            builder.InvokeActionCommand(controllerAction, new object[] { 1 })
                .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1 });

            builder.InvokeActionCommand<int>(controllerAction, arg => new object[] { 1, arg })
                .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1, 5 }, commandArgument: 5);

            builder.InvokeActionWithResult<int>(controllerAction, new object[] { 1 })
                .ActionInvokedWithResult<int>(context, "BuilderController.Action", parameters: new object[] { 1 });
        }

        [Fact]
        public void builder_supports_string_actionnames_with_custom_frame()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");
            var customFrame = Substitute.For<IContentFrame>();

            builder.InvokeAction(customFrame, controllerAction).ActionInvoked(context, "BuilderController.Action", customFrame);

            builder.InvokeActionCommand(customFrame, controllerAction).CommandInvokes(context, "BuilderController.Action", customFrame);

            builder.InvokeActionCommand<int>(customFrame, controllerAction, arg => new object[] { arg })
                .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 5 }, commandArgument: 5);

            builder.InvokeActionWithResult<int>(customFrame, controllerAction).ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame);
        }

        [Fact]
        public void builder_supports_string_actionnames_with_custom_frame_and_parameters()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");
            var customFrame = Substitute.For<IContentFrame>();

            builder.InvokeAction(customFrame, controllerAction, new object[]{1})
                .ActionInvoked(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 });

            builder.InvokeActionCommand(customFrame, controllerAction, new object[] { 1 })
                .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 });

            builder.InvokeActionCommand<int>(customFrame, controllerAction, arg => new object[] { 1, arg })
                .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 1, 5 }, commandArgument: 5);

            builder.InvokeActionWithResult<int>(customFrame, controllerAction, new object[] { 1 })
                .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 });
        }

        [Fact]
        public void builder_supports_controlleractions_with_options()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");

            builder.InvokeAction(controllerAction, options: InvokeOptions.NoProgress)
                .ActionInvoked(context, "BuilderController.Action", options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand(controllerAction, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand<int>(controllerAction, arg => new object[] { arg }, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

            builder.InvokeActionWithResult<int>(controllerAction, options: InvokeOptions.NoProgress)
                .ActionInvokedWithResult<int>(context, "BuilderController.Action", options: InvokeOptions.NoProgress);
        }

        [Fact]
        public void builder_supports_string_actionnames_with_parameters_and_options()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");

            builder.InvokeAction(controllerAction, new object[] { 1 }, options: InvokeOptions.NoProgress)
                .ActionInvoked(context, "BuilderController.Action", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand(controllerAction, new object[] { 1 }, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand<int>(controllerAction, arg => new object[] { 1, arg }, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", parameters: new object[] { 1, 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

            builder.InvokeActionWithResult<int>(controllerAction, new object[] { 1 }, options: InvokeOptions.NoProgress)
                .ActionInvokedWithResult<int>(context, "BuilderController.Action", parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
        }

        [Fact]
        public void builder_supports_string_actionnames_with_custom_frame_and_options()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");
            var customFrame = Substitute.For<IContentFrame>();

            builder.InvokeAction(customFrame, controllerAction, options: InvokeOptions.NoProgress)
                .ActionInvoked(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand(customFrame, controllerAction, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand<int>(customFrame, controllerAction, arg => new object[] { arg }, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 5 }, commandArgument: 5,
                options: InvokeOptions.NoProgress);

            builder.InvokeActionWithResult<int>(customFrame, controllerAction, options: InvokeOptions.NoProgress)
                .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, options: InvokeOptions.NoProgress);
        }

        [Fact]
        public void builder_supports_string_actionnames_with_custom_frame_and_parameters_and_options()
        {
            var controllerAction = ControllerAction.CreateFrom("BuilderController.Action");
            var customFrame = Substitute.For<IContentFrame>();

            builder.InvokeAction(customFrame, controllerAction, new object[] { 1 }, options: InvokeOptions.NoProgress)
                .ActionInvoked(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand(customFrame, controllerAction, new object[] { 1 }, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);

            builder.InvokeActionCommand<int>(customFrame, controllerAction, arg => new object[] { 1, arg }, options: InvokeOptions.NoProgress)
                .CommandInvokes(context, "BuilderController.Action", customFrame, parameters: new object[] { 1, 5 }, commandArgument: 5, options: InvokeOptions.NoProgress);

            builder.InvokeActionWithResult<int>(customFrame, controllerAction, new object[] { 1 }, options: InvokeOptions.NoProgress)
                .ActionInvokedWithResult<int>(context, "BuilderController.Action", customFrame, 
                parameters: new object[] { 1 }, options: InvokeOptions.NoProgress);
        }
    }
}